home *** CD-ROM | disk | FTP | other *** search
- title CTLT - Control-T Interrupt Handler
- page 60,132
-
- ;***********************************************************************
- ;
- ; This routine works by trapping every interrupt 9 (KB_INT) generated by
- ; the keyboard and handled by the IBM BIOS, and after return from BIOS,
- ; inspecting the key which was typed and is now present in the keyboard
- ; ring buffer in the BIOS data segment (40h). If it is the user
- ; interrupt character (normally a CTL-T), it is removed from the buffer
- ; and a status message is displayed on the console screen.
- ;
- ; ***************
- ; *** N O T E ***
- ; ***************
- ;
- ; This code depends upon buffer size, organization, and location, and
- ; pointers thereto, in the IBM BIOS data segment. If a different
- ; keyboard interrupt handler is installed (e.g. one that increases
- ; buffer size), this code will probably fail!
- ;
- ; [02-Aug-84] Nelson H.F. Beebe, College of Science Computer,
- ; University of Utah, Salt Lake City, UT 84112, USA
- ;***********************************************************************
-
- .xlist
- include ascii.inc
- include dos.inc
- .list
-
-
- keyvect segment at 0
- org 9h*4 ; BIOS KB_INT
- keyint label dword
- keyvect ends
-
-
- biosdata segment at 40h
- org 1ah ; See p. A-3 of IBM Tech. Ref. Manual
- buffer_head dw ? ; pointer to head of keyboard buffer
- ; -- address of first available char
- buffer_tail dw ? ; pointer to tail of keyboard buffer
- ; -- address of next empty slot
- ; -- buffer is empty if head=tail
- kb_buffer dw 16 dup (?) ; room for 15 entries
- org $-2
- kb_bufend dw ? ; last word in buffer
- biosdata ends
-
-
- ;***********************************************************************
- ;
- ; INIT_CODE - Code to load and initialize the handler.
- ; Sets up DOS to keep all code before "LASTONE" label safe from
- ; overlaying during system operation.
- ;
- ;***********************************************************************
-
- CODE SEGMENT PARA
- org 100h ; for .COM file
-
- assume cs:code,ds:code
- assume es:biosdata
-
- TYPE_CHAR PROC NEAR
- ; Type character in AL at the current cursor position using the current
- ; character attribute. No translation is done, except that BIOS handles
- ; CR, LF, BEL, and BS as for a teletype.
- ; All registers preserved
-
- push ax
- push bx
- push ax ; save extra copy of character
-
- mov ah,$VIDEO_GETVIDEOSTATE
- int $VIDEO ; get current page in bh
-
- mov ah,$VIDEO_GETATTRCHAR
- int $VIDEO ; get current attribute in ah
- mov bl,ah ; save current attribute
-
- pop ax ; restore character
- mov ah,$VIDEO_SETTTY ; tty output (bl = current attribute)
- int $VIDEO ; character
-
- pop bx ; restore registers
- pop ax
- ret
- TYPE_CHAR ENDP
-
- assume cs:code,ds:code
- TYPE_CRLF PROC NEAR
- ; Type CR LF pair
- ; All registers preserved
- push ax ; save registers
-
- mov al,.CR
- call TYPE_CHAR
-
- mov al,.LF
- call TYPE_CHAR
-
- pop ax ; restore registers
- ret
- TYPE_CRLF ENDP
-
- assume cs:code,ds:code
- TYPE_DEC PROC NEAR
- ; Type integer in AX in decimal, BH = fill character, BL = field width
- ; BL=0 means minimum field width with no fill
- ; All registers preserved
- push ax ; save registers
- push bx
- push cx
- push dx
- push bp
-
- xor cx,cx
- mov cl,bl ; minimum field width
-
- mov bp,ax ; save original number
- test ax,ax ; number < 0?
- jge not_neg ; no
- neg ax ; yes, replace by abs(number)
-
- not_neg:
- push EFLAG ; mark end of number on stack
-
- digit_loop:
- cwd ; sign-extend ax into (ax,dx)
- dec cx ; reduce field width
- div TEN ; number/10 to ax, remainder to dx
- add dx,"0" ; convert to ASCII
- push dx ; save digit
- test ax,ax ; zero yet?
- ja digit_loop ; no, keep dividing
-
- mov dx,bp ; original number
- test dx,dx ; number < 0?
- jge digit_plus ; no
-
- dec cx ; yes, reduce field width
- cmp bh," " ; blank fill?
- jne digit_plus ; no
- mov al,"-" ; yes, save immediate leading
- push ax ; minus sign
-
- digit_plus:
- test cx,cx ; remaining count > 0?
- jle digit_sign ; yes, fill unnecessary
-
- mov al,bh ; fill character
-
- digit_fill:
- push ax ; save fill character
- loop digit_fill ; loop until cx=0
-
- digit_sign:
- mov dx,bp ; original number
- test dx,dx ; number < 0?
- jge digit_type ; no
- cmp bh," " ; blank fill?
- je digit_type ; yes, already saved sign
- mov al,"-" ; no, save sign
- push ax
-
- digit_type:
- pop ax ; digit
- cmp ax,EFLAG ; end of number yet?
- je digit_done ; yes
- call TYPE_CHAR ; type it
- jmp short digit_type ; and go for next digit
-
- digit_done:
- pop bp ; restore registers
- pop dx
- pop cx
- pop bx
- pop ax
- ret ; return to caller
-
- EFLAG dw -1 ; special end-of-number flag
- TEN dw 10
- TYPE_DEC ENDP
-
- assume cs:code,ds:code
- TYPE_HEX PROC NEAR
- ; Type byte in AL as two-character hexadecimal
- ; All registers preserved
- push cx ; save registers
- push bx
- push ax
-
- push ax ; save ax
- mov bh,0 ; clear top of bx
- mov cl,4 ; shift count
- mov bl,al ; byte to print
- shr bl,cl ; left nibble
- mov al,hex_chars[bx]; get character
- call TYPE_CHAR ; and print it
- pop bx ; restore ax into bx
-
- and bx,0fh ; left nibble
- mov al,hex_chars[bx]; get character
- call TYPE_CHAR ; and print it
-
- pop ax ; restore registers
- pop bx
- pop cx
- ret
-
- hex_chars db "0123456789ABCDEF"
- TYPE_HEX ENDP
-
- assume cs:code,ds:code
- TYPE_STRING PROC NEAR
- ; Type NUL-terminated string pointed to by DS:SI (the NUL is not typed).
- ; All registers preserved
- push ax
- push dx
- push si
-
- cld ; read string forward
- msg_loop:
- lodsb ; byte to al, increment si
- test al,al ; message byte = 0?
- jz done_string ; yes, all done
- call TYPE_CHAR ; no, type it
- jmp short msg_loop ; keep printing
-
- done_string:
- pop si
- pop dx
- pop ax
- ret
- TYPE_STRING ENDP
-
- assume cs:code,ds:code
- TYPE_TIME PROC NEAR
- ; Type the current time as hh:mm:ss
- ; All registers preserved
- push ax ; save registers
- push bx
- push cx
- push dx
-
- mov ah,$DOS_GETTIME
- int $DOS
- xor ah,ah ; clear top of ax
- mov al,ch ; hours
- mov bl,0 ; field width=0
- mov bh," " ; fill character
- call TYPE_DEC ; type hh
-
- mov al,":"
- call TYPE_CHAR
-
- mov al,cl ; minutes
- mov bl,2 ; field width
- mov bh," " ; fill character
- call TYPE_DEC ; type mm
-
- mov al,":"
- call TYPE_CHAR
-
- mov al,dh ; seconds
- mov bl,2 ; field width
- mov bh," " ; fill character
- call TYPE_DEC ; type ss
-
- mov al,"."
- call TYPE_CHAR
-
- mov al,dl ; centiseconds
- mov bl,2 ; field width
- mov bh," " ; fill character
- call TYPE_DEC ; now have typed "hh:mm:ss.cc"
-
- pop dx ; restore registers
- pop cx
- pop bx
- pop ax
- ret ; return to caller
- TYPE_TIME ENDP
-
- assume cs:code,ds:code
- assume es:biosdata
-
- KEY PROC NEAR
- start:
- jmp init_code ; done only once at startup
-
- key_call: ; Far JMP to keyboard interrupt
- jmp far ptr es:0 ; filled in at runtime
- ; db 0eah
- ; dw 0,0
-
-
- old_ip equ [bp+2] ; bp = entry_sp-2
- old_cs equ [bp+4]
- old_fl equ [bp+6]
-
- key_rtne:
- sti ; turn interrupts back on
-
- push ax ; save registers
- push bx
- push cx
- push dx
- push bp
- push ds
- push es
- push di
- push si
-
- mov bx,cs
- mov ds,bx ; establish local DS = CS
-
- mov bx,biosdata
- mov es,bx ; establish ES -> BIOSDATA
-
- ; First call original KB_INT BIOS code to actually retrieve the character
- ; over the keyboard port and do its massive amount of bookkeeping
-
- pushf ; flags to fake interrupt call
- mov bx,offset key_call+1 ; get address of ROM code for keyboard
- call dword ptr [bx] ; call ROM code
-
- ;-----------------------------------------------------------------------
- ; enter critical section -- no interrupts allowed until character retrieved
- ; and buffer pointers updated
-
- cli ; interrupts off while char retrieved
- mov bx,es:buffer_tail ; next available slot in buffer
- dec bx ; backup 2 bytes
- dec bx
- cmp bx,offset kb_buffer ; backed up before start?
- jae nowrap ; no
- mov bx,offset kb_bufend ; yes, move to end of buffer
- nowrap:
- mov ax,es:[bx] ; char in al, scan code in ah
-
- cmp al,.ctlt ; CTL-T?
- jne done ; no
-
- mov es:buffer_tail,bx ; remove last character (the CTL-T)
- sti ; interrupts back on
-
- ; end critical section
- ;-----------------------------------------------------------------------
-
- call TYPE_TIME
-
- mov si,offset csip_msg
- call TYPE_STRING
-
- mov al,old_cs+1
- call TYPE_HEX
-
- mov al,old_cs
- call TYPE_HEX
-
- mov al,":"
- call TYPE_CHAR
-
- mov al,old_ip+1
- call TYPE_HEX
-
- mov al,old_ip
- call TYPE_HEX
-
- mov si,offset flags_msg
- call TYPE_STRING
-
- mov al,old_fl+1
- call TYPE_HEX
-
- mov al,old_fl
- call TYPE_HEX
-
- call TYPE_CRLF
-
- done_int:
- pop si ; restore saved registers
- pop di
- pop es
- pop ds
- pop bp
- pop dx
- pop cx
- pop bx
- pop ax
- iret ; return from interrupt
-
- csip_msg db " CS:IP ",0
- flags_msg db " Flags ",0
-
- KEY ENDP
-
-
- lastone: ; all code after this label is freed to DOS after
- ; program initialization
-
- copyrt db 'CONTROL-T Handler -- Version 1.0 -- Public Domain 1984'
- db .CR,.LF
- db 'Nelson H.F. Beebe, University of Utah, Salt Lake City, '
- db 'UT 84112, USA'
- db .CR,.LF,0
-
- assume cs:code,ds:code
- assume es:keyvect
- INIT_CODE PROC NEAR
-
- ; Initialize KEYBOARD interrupt system
-
- ;-----------------------------------------------------------------------
- ; enter critical section -- no interrupts while adjusting interrupt vector
- ;
- cli ; interrupts off
- mov ax,keyvect ; Get address to interrupt vector
- mov es,ax ; Save in ES
- mov ax,es:keyint ; Get address to interrupt routine
- mov bx,offset key_call+1 ; Address to place to save vector
- mov [bx],ax ; Save interrupt address
- mov ax,es:keyint[2] ; Get interrupt segment for routine
- mov [bx+2],ax ; Save it too
- mov es:keyint,offset key_rtne ; Now, replace with own address
- mov ax,cs ; Save segment in interrupt vector
- mov es:keyint[2],ax
- sti ; interrupts back on
-
- ; end critical section
- ;-----------------------------------------------------------------------
-
- ; Now, print out acknowledgement to user monitor and exit
-
- mov ax,cs ; Set up segment to this routine
- mov ds,ax
- mov si,offset copyrt ; Now, print out copyright message
- call TYPE_STRING
- mov dx,offset lastone ; Save all code up to "LASTONE" label
- int 27h ; No return needed
-
- INIT_CODE ENDP
- CODE ENDS
- END START